<?php

namespace maotool\core;

use maotool\object\ObjUtil;
use maotool\util\ArrayUtil;
use maotool\util\IniFileUtil;
use maotool\util\PathUtil;

class Env
{

    /**
     * 环境变量数据
     * @var array
     */
    protected $data = [];

    /**
     * 获取环境变量值
     * @param string|null $name 环境变量名（支持多级配置 .号分割）
     * @param mixed|null $default 默认值
     * @return mixed
     */
    public function get($name = null, $default = null)
    {
        $data = [];
        // 读取系统环境变量
        if (function_exists('getenv')) {
            foreach (getenv() as $key => $value) {
                $data[$key] = $value;
            }
        }
        // 读取程序预设的环境变量
        foreach ($_ENV as $key => $value) {
            $data[$key] = $value;
        }
        // 读取.env文件的配置变量
        $envPath = PathUtil::projectEnvPath();
        if ($envPath !== false) {
            $env = IniFileUtil::parse($envPath);
            foreach ($env as $key => $value) {
                $data[$key] = $value;
            }
        }
        // 读取程序的环境变量
        foreach ($this->data as $key => $value) {
            $data[$key] = $value;
        }
        if (ObjUtil::isNotNull($name)) {
            if (is_string($name)) {
                $name = explode(".", $name);
                foreach ($name as $index => $item) {
                    if (ArrayUtil::keyNotExists($item, $data)) {
                        if (ObjUtil::isNull($default)) {
                            return null;
                        } else {
                            if (($index + 1) == count($name)) {
                                $data[$item] = null;
                            } else {
                                $data[$item] = [];
                            }
                        }
                    }
                    $data = &$data[$item];
                }
            }
        }
        if (is_null($data)) {
            $data = $default;
        }
        return $data;
    }

    /**
     * 设置环境变量值
     * @param string $name 环境变量
     * @param mixed|null $value 值
     * @return bool
     */
    public function set($name, $value = null)
    {
        $name = explode(".", $name);
        $data = &$this->data;
        foreach ($name as $index => $item) {
            if (ArrayUtil::keyNotExists($item, $data)) {
                if (($index + 1) == count($name)) {
                    $data[$item] = null;
                } else {
                    $data[$item] = [];
                }
            }
            $data = &$data[$item];
        }
        if (ObjUtil::equals($data, $value)) {
            $data = $value;
            return false;
        } else {
            $data = $value;
            return true;
        }
    }

    /**
     * 检测配置是否存在
     * @access public
     * @param string $name
     * @return bool
     */
    public function has($name)
    {
        return !is_null($this->get($name));
    }

    /**
     * 移除配置
     * @access public
     * @param string $name
     * @return bool
     */
    public function remove($name)
    {
        $name = explode(".", $name);
        $data = &$this->data;
        foreach ($name as $index => $item) {
            if (ArrayUtil::keyNotExists($item, $data)) {
                return false;
            }
            if (($index + 1) == count($name)) {
                unset($data[$item]);
                return true;
            }
            $data = &$data[$item];
        }
        return false;
    }

    /**
     * 重置配置参数
     * @access public
     * @return void
     */
    public function reset()
    {
        $this->data = [];
    }

    /**
     * 设置配置
     * @access public
     * @param string $name 参数名
     * @param mixed $value 值
     */
    public function __set($name, $value)
    {
        return $this->set($name, $value);
    }

    /**
     * 获取配置参数
     * @access public
     * @param string $name 参数名
     * @return mixed
     */
    public function __get($name)
    {
        return $this->get($name);
    }

    /**
     * 检测是否存在参数
     * @access public
     * @param string $name 参数名
     * @return bool
     */
    public function __isset($name)
    {
        return $this->has($name);
    }

    /**
     * 配置转为字符串
     * @return string
     */
    public function __tostring()
    {
        return json_encode($this->get());
    }

}
